You can now set all sorts of properties in any order you wan, whether or
authorJonathan Blandford <jrb@redhat.com>
Wed, 16 May 2001 00:23:30 +0000 (00:23 +0000)
committerJonathan Blandford <jrb@src.gnome.org>
Wed, 16 May 2001 00:23:30 +0000 (00:23 +0000)
Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>

* gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
in any order you wan, whether or not the column is added to the
tree, or the tree is realized.  Yay!

* gtk/gtktreeviewcolumn.c
(gtk_tree_view_column_setup_sort_column_id_callback): handle
sorting columns a lot saner

* gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
new function to actually set wether or not a column is
reorderable.

* gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
if we have 'em.

* gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
Fix nasty bug where we were showing the button just before
realizing it.  As a result, the parent window was
tree_view->window instead of tree_view->priv->header_window.

* gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
to let you easily reorder a list or tree.

13 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
gtk/gtktreeprivate.h
gtk/gtktreeview.c
gtk/gtktreeview.h
gtk/gtktreeviewcolumn.c
gtk/gtktreeviewcolumn.h
tests/testtreecolumns.c

index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index cd8745b28ded5c241981f61624e5870fcef19ab9..f85c19820e7023e00a729d5c7d57fcaaae3f1ded 100644 (file)
@@ -1,3 +1,28 @@
+Tue May 15 20:13:24 2001  Jonathan Blandford  <jrb@redhat.com>
+
+       * gtk/gtktreeviewcolumn.c: You can now set all sorts of properties
+       in any order you wan, whether or not the column is added to the
+       tree, or the tree is realized.  Yay!
+
+       * gtk/gtktreeviewcolumn.c
+       (gtk_tree_view_column_setup_sort_column_id_callback): handle
+       sorting columns a lot saner
+
+       * gtk/gtktreeviewcolumn.c (gtk_tree_view_column_set_reorderable):
+       new function to actually set wether or not a column is
+       reorderable.
+
+       * gtk/gtktreeview.c (gtk_tree_view_unrealize): Only destroy things
+       if we have 'em.
+
+       * gtk/gtktreeviewcolumn.c (_gtk_tree_view_column_set_tree_view):
+       Fix nasty bug where we were showing the button just before
+       realizing it.  As a result, the parent window was
+       tree_view->window instead of tree_view->priv->header_window.
+
+       * gtk/gtktreeview.c (gtk_tree_view_set_reorderable): new property
+       to let you easily reorder a list or tree.
+
 2001-05-15  Alexander Larsson  <alla@lysator.liu.se>
 
        * gtk/gtkpacker.c: Apply patch from John Margaglione that converts
index 2eeac5b74232a659deb00170de42be61668cdf74..7d6be42a22201ba97110ca13d2dec8772b901467 100644 (file)
@@ -153,6 +153,7 @@ struct _GtkTreeViewPrivate
   gfloat scroll_to_row_align;
   gfloat scroll_to_col_align;
 
+  guint reorderable : 1;
   guint header_has_focus : 1;
   guint drag_column_window_state : 3;
   /* hint to display rows in alternating colors */
@@ -246,12 +247,13 @@ GtkTreePath *_gtk_tree_view_find_path                 (GtkTreeView       *tree_v
 void         _gtk_tree_view_update_size               (GtkTreeView       *tree_view);
 
 
-void _gtk_tree_view_column_create_button    (GtkTreeViewColumn *column);
 void _gtk_tree_view_column_realize_button   (GtkTreeViewColumn *column);
 void _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column);
 void _gtk_tree_view_column_set_tree_view    (GtkTreeViewColumn *column,
                                             GtkTreeView       *tree_view);
 void _gtk_tree_view_column_unset_tree_view  (GtkTreeViewColumn *column);
+void _gtk_tree_view_column_set_width        (GtkTreeViewColumn *column,
+                                            gint               width);
 void _gtk_tree_view_column_start_drag       (GtkTreeView       *tree_view,
                                             GtkTreeViewColumn *column);
 
index 82f1621e2f52a24f7427bd3c5a6f9629ee5866fd..2895e4fe1ec63a01a6fda67e654200a91eaa6e51 100644 (file)
@@ -107,6 +107,7 @@ enum {
   PROP_HEADERS_VISIBLE,
   PROP_HEADERS_CLICKABLE,
   PROP_EXPANDER_COLUMN,
+  PROP_REORDERABLE,
   PROP_RULES_HINT
 };
 
@@ -424,6 +425,14 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
                                                      0,
                                                      G_PARAM_READWRITE));
 
+  g_object_class_install_property (o_class,
+                                   PROP_REORDERABLE,
+                                   g_param_spec_boolean ("reorderable",
+                                                        _("Reorderable"),
+                                                        _("View is reorderable"),
+                                                        FALSE,
+                                                        G_PARAM_READWRITE));
+
   g_object_class_install_property (o_class,
                                    PROP_RULES_HINT,
                                    g_param_spec_boolean ("rules_hint",
@@ -542,7 +551,7 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   tree_view->priv->pressed_button = -1;
   tree_view->priv->press_start_x = -1;
   tree_view->priv->press_start_y = -1;
-
+  tree_view->priv->reorderable = FALSE;
   gtk_tree_view_set_adjustments (tree_view, NULL, NULL);
   _gtk_tree_view_update_size (tree_view);
 }
@@ -582,6 +591,9 @@ gtk_tree_view_set_property (GObject         *object,
     case PROP_EXPANDER_COLUMN:
       gtk_tree_view_set_expander_column (tree_view, g_value_get_uint (value));
       break;
+    case PROP_REORDERABLE:
+      gtk_tree_view_set_reorderable (tree_view, g_value_get_boolean (value));
+      break;
     case PROP_RULES_HINT:
       gtk_tree_view_set_rules_hint (tree_view, g_value_get_boolean (value));
       break;
@@ -617,6 +629,9 @@ gtk_tree_view_get_property (GObject         *object,
     case PROP_EXPANDER_COLUMN:
       g_value_set_uint (value, tree_view->priv->expander_column);
       break;
+    case PROP_REORDERABLE:
+      g_value_set_boolean (value, tree_view->priv->reorderable);
+      break;
     case PROP_RULES_HINT:
       g_value_set_boolean (value, tree_view->priv->has_rules);
       break;
@@ -717,7 +732,7 @@ gtk_tree_view_destroy (GtkObject *object)
 /* GtkWidget Methods
  */
 
-/* GtkWidget:;map helper */
+/* GtkWidget::map helper */
 static void
 gtk_tree_view_map_buttons (GtkTreeView *tree_view)
 {
@@ -947,11 +962,19 @@ gtk_tree_view_unrealize (GtkWidget *widget)
       tree_view->priv->drag_highlight_window = NULL;
     }
 
-  gdk_cursor_destroy (tree_view->priv->cursor_drag);
-  gdk_gc_destroy (tree_view->priv->xor_gc);
+  if (tree_view->priv->cursor_drag)
+    {
+      gdk_cursor_destroy (tree_view->priv->cursor_drag);
+      tree_view->priv->cursor_drag = NULL;
+    }
 
-  /* GtkWidget::unrealize destroys children and widget->window */
+  if (tree_view->priv->xor_gc)
+    {
+      gdk_gc_destroy (tree_view->priv->xor_gc);
+      tree_view->priv->xor_gc = NULL;
+    }
 
+  /* GtkWidget::unrealize destroys children and widget->window */
   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
 }
@@ -975,7 +998,7 @@ gtk_tree_view_size_request_buttons (GtkTreeView *tree_view)
 
           gtk_widget_size_request (column->button, &requisition);
 
-          gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
+          _gtk_tree_view_column_set_width (column, MAX (column->width, requisition.width));
           tree_view->priv->header_height = MAX (tree_view->priv->header_height, requisition.height);
         }
     }
@@ -1391,7 +1414,7 @@ gtk_tree_view_button_release_column_resize (GtkWidget      *widget,
   gdk_pointer_ungrab (event->time);
 
   width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget), i, &x);
-  gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
+  _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), i), width);
 
   return TRUE;
 }
@@ -1862,7 +1885,7 @@ gtk_tree_view_motion_resize_column (GtkWidget      *widget,
   new_width = gtk_tree_view_new_column_width (GTK_TREE_VIEW (widget),
                                              GTK_TREE_VIEW (widget)->priv->drag_pos, &x);
   if (x != GTK_TREE_VIEW (widget)->priv->x_drag)
-    gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
+    _gtk_tree_view_column_set_width (gtk_tree_view_get_column (GTK_TREE_VIEW (widget), GTK_TREE_VIEW (widget)->priv->drag_pos), new_width);
 
   /* FIXME: Do we need to scroll */
   _gtk_tree_view_update_size (GTK_TREE_VIEW (widget));
@@ -4672,10 +4695,10 @@ gtk_tree_view_insert_iter_height (GtkTreeView *tree_view,
 
       if (i == tree_view->priv->expander_column &&
           TREE_VIEW_DRAW_EXPANDERS (tree_view))
-       gtk_tree_view_column_set_width (column,
+       _gtk_tree_view_column_set_width (column,
                                         MAX (column->width, depth * tree_view->priv->tab_offset + width));
       else
-        gtk_tree_view_column_set_width (column,
+        _gtk_tree_view_column_set_width (column,
                                         MAX (column->width, width));
 
       ++i;
@@ -4777,10 +4800,10 @@ gtk_tree_view_calc_size (GtkTreeView *tree_view,
            }
          if (i == tree_view->priv->expander_column &&
               TREE_VIEW_DRAW_EXPANDERS (tree_view))
-            gtk_tree_view_column_set_width (column,
+            _gtk_tree_view_column_set_width (column,
                                             MAX (column->width, depth * tree_view->priv->tab_offset + width));
          else
-            gtk_tree_view_column_set_width (column, MAX (column->width, width));
+            _gtk_tree_view_column_set_width (column, MAX (column->width, width));
        }
 
       _gtk_rbtree_node_set_height (tree, temp, max_height);
@@ -4924,7 +4947,7 @@ gtk_tree_view_check_dirty (GtkTreeView *tree_view)
               if (column->button)
                 w = MAX (w, column->button->requisition.width);
 
-              gtk_tree_view_column_set_width (column, w);
+              _gtk_tree_view_column_set_width (column, w);
            }
        }
     }
@@ -5141,12 +5164,14 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
       if (cur_column->visible == FALSE)
        continue;
 
-      if (tree_view->priv->column_drop_func &&
-         (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
+      /* If it's not the column moving and func tells us to skip over the column, we continue. */
+      if (left_column != column && cur_column != column &&
+         tree_view->priv->column_drop_func &&
+         ! (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data))
        {
          left_column = cur_column;
          continue;
-       }
+       } 
       reorder = g_new (GtkTreeViewColumnReorder, 1);
       reorder->left_column = left_column;
       left_column = reorder->right_column = cur_column;
@@ -5155,12 +5180,35 @@ gtk_tree_view_set_column_drag_info (GtkTreeView       *tree_view,
     }
 
   /* Add the last one */
-  reorder = g_new (GtkTreeViewColumnReorder, 1);
-  reorder->left_column = left_column;
-  reorder->right_column = NULL;
-  tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
+  if (tree_view->priv->column_drop_func == NULL ||
+      ((left_column != column) &&
+       (* tree_view->priv->column_drop_func) (tree_view, column, left_column, cur_column, tree_view->priv->column_drop_func_data)))
+    {
+      reorder = g_new (GtkTreeViewColumnReorder, 1);
+      reorder->left_column = left_column;
+      reorder->right_column = NULL;
+      tree_view->priv->column_drag_info = g_list_append (tree_view->priv->column_drag_info, reorder);
+    }
+
+  /* We quickly check to see if it even makes sense to reorder columns. */
+  /* If there is nothing that can be moved, then we return */
+
+  if (tree_view->priv->column_drag_info == NULL)
+    return;
 
-  /* Now we want to fill in the ranges for the columns, now that we've isolated them */
+  /* We know there are always 2 slots possbile, as you can always return column. */
+  /* If that's all there is, return */
+  if (tree_view->priv->column_drag_info->next->next == NULL &&
+      ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->data)->right_column == column &&
+      ((GtkTreeViewColumnReorder *)tree_view->priv->column_drag_info->next->data)->left_column == column)
+    {
+      for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
+       g_free (tmp_list->data);
+      g_list_free (tree_view->priv->column_drag_info);
+      tree_view->priv->column_drag_info = NULL;
+      return;
+    }
+  /* We fill in the ranges for the columns, now that we've isolated them */
   left = - TREE_VIEW_COLUMN_DRAG_DEAD_MULTIPLIER (tree_view);
 
   for (tmp_list = tree_view->priv->column_drag_info; tmp_list; tmp_list = tmp_list->next)
@@ -5991,14 +6039,13 @@ gtk_tree_view_remove_column (GtkTreeView       *tree_view,
 
   tree_view->priv->columns = g_list_remove (tree_view->priv->columns, column);
 
-  g_object_unref (G_OBJECT (column));
-
   tree_view->priv->n_columns--;
 
   if (GTK_WIDGET_REALIZED (tree_view))
     {
       GList *list;
 
+      _gtk_tree_view_column_unrealize_button (column);
       for (list = tree_view->priv->columns; list; list = list->next)
        {
          column = GTK_TREE_VIEW_COLUMN (list->data);
@@ -6013,7 +6060,9 @@ gtk_tree_view_remove_column (GtkTreeView       *tree_view,
       gtk_widget_queue_resize (GTK_WIDGET (tree_view));
     }
 
+  g_object_unref (G_OBJECT (column));
   g_signal_emit (G_OBJECT (tree_view), tree_view_signals[COLUMNS_CHANGED], 0);
+
   return tree_view->priv->n_columns;
 }
 
@@ -6048,16 +6097,16 @@ gtk_tree_view_insert_column (GtkTreeView       *tree_view,
 
   tree_view->priv->columns = g_list_insert (tree_view->priv->columns,
                                            column, position);
-  _gtk_tree_view_column_set_tree_view (column, tree_view);
-  _gtk_tree_view_column_create_button (column);
-
   tree_view->priv->n_columns++;
 
+  _gtk_tree_view_column_set_tree_view (column, tree_view);
 
   if (GTK_WIDGET_REALIZED (tree_view))
     {
       GList *list;
 
+      _gtk_tree_view_column_realize_button (column);
+
       for (list = tree_view->priv->columns; list; list = list->next)
        {
          column = GTK_TREE_VIEW_COLUMN (list->data);
@@ -6718,6 +6767,50 @@ gtk_tree_view_map_expanded_rows (GtkTreeView            *tree_view,
   gtk_tree_path_free (path);
 }
 
+static GtkTargetEntry row_targets[] = {
+  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, 0 }
+};
+
+/**
+ * gtk_tree_view_set_reorderable:
+ * @tree_view: A #GtkTreeView.
+ * @reorderable: TRUE, if the tree can be reordered.
+ * 
+ * This function is a convenience function to allow you to reorder models that
+ * support the #GtkDragSourceIface and the #GtkDragDestIface.  Both
+ * #GtkTreeStore and #GtkListStore support these.  If @reorderable is TRUE, then
+ * the user can reorder the model by dragging and dropping columns.  The
+ * developer will can listen to these changes by connecting to the model's
+ * signals.
+ *
+ * This function does not give you any degree of control over the order -- any
+ * reorderering is allowed.  If more control is needed, you should probably
+ * handle drag and drop manually.
+ **/
+void
+gtk_tree_view_set_reorderable (GtkTreeView *tree_view,
+                              gboolean     reorderable)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+
+  if (tree_view->priv->reorderable == (reorderable?TRUE:FALSE))
+    return;
+
+  gtk_tree_view_set_rows_drag_source (tree_view,
+                                      GDK_BUTTON1_MASK,
+                                      row_targets,
+                                      G_N_ELEMENTS (row_targets),
+                                      GDK_ACTION_MOVE,
+                                      NULL, NULL);
+  gtk_tree_view_set_rows_drag_dest (tree_view,
+                                    row_targets,
+                                    G_N_ELEMENTS (row_targets),
+                                    GDK_ACTION_MOVE,
+                                    NULL, NULL);
+
+  g_object_notify (G_OBJECT (tree_view), "reorderable");
+}
+
 
 /**
  * gtk_tree_view_get_path_at_pos:
@@ -7258,14 +7351,17 @@ gtk_tree_view_get_dest_row_at_pos (GtkTreeView             *tree_view,
    */
 
   g_return_val_if_fail (tree_view != NULL, FALSE);
-  g_return_val_if_fail (tree_view->priv->tree != NULL, FALSE);
   g_return_val_if_fail (drag_x >= 0, FALSE);
   g_return_val_if_fail (drag_y >= 0, FALSE);
   g_return_val_if_fail (tree_view->priv->bin_window != NULL, FALSE);
 
+
   if (path)
     *path = NULL;
 
+  if (tree_view->priv->tree == NULL)
+    return FALSE;
+
   /* remember that drag_x and drag_y are in widget coords, convert to tree window */
 
   gtk_tree_view_widget_to_tree_coords (tree_view, drag_x, drag_y,
index 9d2131eb7c104631a60997c25471515e120f0bc9..4a63b9a053a95c9186d2be46f5f706f15601f604 100644 (file)
@@ -173,6 +173,9 @@ gboolean               gtk_tree_view_collapse_row                  (GtkTreeView
 void                   gtk_tree_view_map_expanded_rows             (GtkTreeView               *tree_view,
                                                                    GtkTreeViewMappingFunc     func,
                                                                    gpointer                   data);
+void                   gtk_tree_view_set_reorderable               (GtkTreeView               *tree_view,
+                                                                   gboolean                   reorderable);
+
 
 /* Layout information */
 gboolean               gtk_tree_view_get_path_at_pos               (GtkTreeView               *tree_view,
@@ -221,6 +224,7 @@ void                   gtk_tree_view_set_rows_drag_dest            (GtkTreeView
 void                   gtk_tree_view_unset_rows_drag_source        (GtkTreeView               *tree_view);
 void                   gtk_tree_view_unset_rows_drag_dest          (GtkTreeView               *tree_view);
 
+
 /* These are useful to implement your own custom stuff. */
 void                   gtk_tree_view_set_drag_dest_row             (GtkTreeView               *tree_view,
                                                                    GtkTreePath               *path,
index 83662fbf57d2a922d3f05ea53532f6a5f0793d93..28d7d6452b726699e81b2c1578e93f8e3559b51f 100644 (file)
@@ -43,6 +43,7 @@ enum
   PROP_CLICKABLE,
   PROP_WIDGET,
   PROP_ALIGNMENT,
+  PROP_REORDERABLE,
   PROP_SORT_INDICATOR,
   PROP_SORT_ORDER
 };
@@ -54,23 +55,58 @@ enum
 };
 
 
-static void gtk_tree_view_column_init            (GtkTreeViewColumn      *tree_column);
-static void gtk_tree_view_column_class_init      (GtkTreeViewColumnClass *klass);
-static void gtk_tree_view_column_set_attributesv (GtkTreeViewColumn      *tree_column,
-                                                 va_list                 args);
-static void gtk_real_tree_column_clicked         (GtkTreeViewColumn      *tree_column);
-static void gtk_tree_view_column_set_property    (GObject                *object,
-                                                 guint                   prop_id,
-                                                 const GValue           *value,
-                                                 GParamSpec             *pspec);
-static void gtk_tree_view_column_get_property    (GObject                *object,
-                                                 guint                   prop_id,
-                                                 GValue                 *value,
-                                                 GParamSpec             *pspec);
-static void gtk_tree_view_column_finalize        (GObject                *object);
-static void gtk_tree_view_column_sort_column_changed (GtkTreeSortable   *sortable,
-                                                     GtkTreeViewColumn *column);
-static void update_button_contents (GtkTreeViewColumn *tree_column);
+/* Type methods */
+static void gtk_tree_view_column_init                          (GtkTreeViewColumn       *tree_column);
+static void gtk_tree_view_column_class_init                    (GtkTreeViewColumnClass  *klass);
+
+/* GObject methods */
+static void gtk_tree_view_column_set_property                  (GObject                 *object,
+                                                               guint                    prop_id,
+                                                               const GValue            *value,
+                                                               GParamSpec              *pspec);
+static void gtk_tree_view_column_get_property                  (GObject                 *object,
+                                                               guint                    prop_id,
+                                                               GValue                  *value,
+                                                               GParamSpec              *pspec);
+static void gtk_tree_view_column_finalize                      (GObject                 *object);
+
+/* Button handling code */ 
+static void gtk_tree_view_column_create_button                 (GtkTreeViewColumn       *tree_column);
+static void gtk_tree_view_column_update_button                 (GtkTreeViewColumn       *tree_column);
+
+/* Button signal handlers */
+static gint gtk_tree_view_column_button_passive_func           (GtkWidget               *widget,
+                                                               GdkEvent                *event,
+                                                               gpointer                 data);
+static void gtk_tree_view_column_button_realize                (GtkWidget               *widget,
+                                                               gpointer                 data);
+static void gtk_tree_view_column_button_pressed                (GtkWidget               *widget,
+                                                               gpointer                 data);
+static void gtk_tree_view_column_button_released               (GtkWidget               *widget,
+                                                               gpointer                 data);
+static void gtk_tree_view_column_button_clicked                (GtkWidget               *widget,
+                                                               gpointer                 data);
+static gint gtk_tree_view_column_button_motion_event           (GtkWidget               *widget,
+                                                               GdkEventMotion          *event,
+                                                               gpointer                 data);
+
+/* Property handlers */
+static void gtk_tree_view_model_property_changed               (GtkTreeView             *view,
+                                                               guint                    n_pspecs,
+                                                               GParamSpec             **pspecs,
+                                                               GtkTreeViewColumn       *tree_column);
+static void gtk_tree_view_model_sort_column_changed            (GtkTreeSortable         *sortable,
+                                                               GtkTreeViewColumn       *tree_column);
+
+/* Internal functions */
+static void gtk_tree_view_column_sort                          (GtkTreeViewColumn       *tree_column,
+                                                               gpointer                 data);
+static void gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn       *tree_column);
+static void gtk_tree_view_column_set_clickable_real            (GtkTreeViewColumn       *tree_column);
+static void gtk_tree_view_column_set_attributesv               (GtkTreeViewColumn       *tree_column,
+                                                               va_list                  args);
+
+
 
 
 static GtkObjectClass *parent_class = NULL;
@@ -112,7 +148,7 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
 
   parent_class = g_type_class_peek_parent (class);
 
-  class->clicked = gtk_real_tree_column_clicked;
+  class->clicked = NULL;
 
   object_class->finalize = gtk_tree_view_column_finalize;
   object_class->set_property = gtk_tree_view_column_set_property;
@@ -217,6 +253,14 @@ gtk_tree_view_column_class_init (GtkTreeViewColumnClass *class)
                                                        0.5,
                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
 
+  g_object_class_install_property (object_class,
+                                   PROP_REORDERABLE,
+                                   g_param_spec_boolean ("reorderable",
+                                                        _("Reorderable"),
+                                                        _("Wether the column can be reordered around the headers"),
+                                                        FALSE,
+                                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
+
   g_object_class_install_property (object_class,
                                    PROP_SORT_INDICATOR,
                                    g_param_spec_boolean ("sort_indicator",
@@ -246,22 +290,36 @@ gtk_tree_view_column_init (GtkTreeViewColumn *tree_column)
   tree_column->button = NULL;
   tree_column->xalign = 0.0;
   tree_column->width = 1;
+  tree_column->requested_width = -1;
   tree_column->min_width = -1;
   tree_column->max_width = -1;
-  tree_column->model_changed_signal = 0;
   tree_column->cell = NULL;
   tree_column->attributes = NULL;
   tree_column->column_type = GTK_TREE_VIEW_COLUMN_AUTOSIZE;
   tree_column->visible = TRUE;
-  tree_column->button_active = FALSE;
+  tree_column->clickable = FALSE;
   tree_column->dirty = TRUE;
   tree_column->sort_order = GTK_TREE_SORT_ASCENDING;
   tree_column->show_sort_indicator = FALSE;
+  tree_column->property_changed_signal = 0;
   tree_column->sort_clicked_signal = 0;
   tree_column->sort_column_changed_signal = 0;
+  tree_column->clickable_signal = 0;
   tree_column->sort_column_id = -1;
-  tree_column->reorderable = 1;
-  tree_column->maybe_reordered = 0;
+  tree_column->reorderable = FALSE;
+  tree_column->maybe_reordered = FALSE;
+}
+
+static void
+gtk_tree_view_column_finalize (GObject *object)
+{
+  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
+
+  if (tree_column->func_data && tree_column->destroy)
+    (tree_column->destroy) (tree_column->func_data);
+
+  g_slist_free (tree_column->attributes);
+  g_free (tree_column->title);
 }
 
 static void
@@ -421,24 +479,219 @@ gtk_tree_view_column_get_property (GObject         *object,
     }
 }
 
+/* Helper functions
+ */
+
+/* Button handling code
+ */
 static void
-gtk_tree_view_column_finalize (GObject *object)
+gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
 {
-  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) object;
+  GtkTreeView *tree_view;
+  GtkWidget *child;
+  GtkWidget *hbox;
 
-  if (tree_column->func_data && tree_column->destroy)
-    (tree_column->destroy) (tree_column->func_data);
+  tree_view = (GtkTreeView *) tree_column->tree_view;
 
-  g_slist_free (tree_column->attributes);
-  g_free (tree_column->title);
+  g_return_if_fail (tree_view != NULL);
+  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
+  g_return_if_fail (tree_column->button == NULL);
+
+  gtk_widget_push_composite_child ();
+  tree_column->button = gtk_button_new ();
+  gtk_widget_pop_composite_child ();
+
+  /* make sure we own a reference to it as well. */
+  gtk_widget_set_parent (tree_column->button, GTK_WIDGET (tree_view));
+  
+  gtk_signal_connect (GTK_OBJECT (tree_column->button), "realize",
+                     (GtkSignalFunc) gtk_tree_view_column_button_realize,
+                     NULL);
+  gtk_signal_connect (GTK_OBJECT (tree_column->button), "clicked",
+                     (GtkSignalFunc) gtk_tree_view_column_button_clicked,
+                     (gpointer) tree_column);
+  gtk_signal_connect (GTK_OBJECT (tree_column->button), "pressed",
+                     (GtkSignalFunc) gtk_tree_view_column_button_pressed,
+                     (gpointer) tree_column);
+  gtk_signal_connect (GTK_OBJECT (tree_column->button), "motion_notify_event",
+                     (GtkSignalFunc) gtk_tree_view_column_button_motion_event,
+                     (gpointer) tree_column);
+  gtk_signal_connect (GTK_OBJECT (tree_column->button), "released",
+                     (GtkSignalFunc) gtk_tree_view_column_button_released,
+                     (gpointer) tree_column);
+
+  tree_column->alignment = gtk_alignment_new (tree_column->xalign, 0.5, 0.0, 0.0);
+
+  hbox = gtk_hbox_new (FALSE, 2);
+  tree_column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
+
+  if (tree_column->child)
+    child = tree_column->child;
+  else
+    {
+      child = gtk_label_new (tree_column->title);
+      gtk_widget_show (child);
+    }
+
+  if (tree_column->xalign <= 0.5)
+    gtk_box_pack_end (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
+  else
+    gtk_box_pack_start (GTK_BOX (hbox), tree_column->arrow, FALSE, FALSE, 0);
+
+  gtk_box_pack_start (GTK_BOX (hbox), tree_column->alignment, TRUE, TRUE, 0);
+        
+  gtk_container_add (GTK_CONTAINER (tree_column->alignment), child);
+  gtk_container_add (GTK_CONTAINER (tree_column->button), hbox);
+
+  gtk_widget_show (hbox);
+  gtk_widget_show (tree_column->alignment);
+  gtk_tree_view_column_update_button (tree_column);
+
+  gtk_tree_view_column_set_clickable_real (tree_column);
 }
 
-/* used to make the buttons 'unclickable' */
+static void 
+gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
+{
+  GtkWidget *hbox;
+  GtkWidget *alignment;
+  GtkWidget *arrow;
+  GtkWidget *current_child;
+
+
+  /* Create a button if necessary */
+  if (tree_column->visible &&
+      tree_column->button == NULL &&
+      tree_column->tree_view &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
+    gtk_tree_view_column_create_button (tree_column);
+  
+  if (! tree_column->button)
+    return;
+
+  hbox = GTK_BIN (tree_column->button)->child;
+  alignment = tree_column->alignment;
+  arrow = tree_column->arrow;
+  current_child = GTK_BIN (alignment)->child;
+
+  /* Set up the actual button */
+  gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
+                    0.5, 0.0, 0.0);
+      
+  if (tree_column->child)
+    {
+      if (current_child != tree_column->child)
+       {
+         gtk_container_remove (GTK_CONTAINER (alignment),
+                               current_child);
+         gtk_container_add (GTK_CONTAINER (alignment),
+                            tree_column->child);
+       }
+    }
+  else 
+    {
+      if (current_child == NULL)
+       {
+         current_child = gtk_label_new (NULL);
+         gtk_widget_show (current_child);
+         gtk_container_add (GTK_CONTAINER (alignment),
+                            current_child);
+       }
+
+      g_return_if_fail (GTK_IS_LABEL (current_child));
+
+      if (tree_column->title)
+       gtk_label_set_text (GTK_LABEL (current_child),
+                           tree_column->title);
+      else
+       gtk_label_set_text (GTK_LABEL (current_child),
+                           "");
+    }
+
+  switch (tree_column->sort_order)
+    {
+    case GTK_TREE_SORT_ASCENDING:
+      gtk_arrow_set (GTK_ARROW (arrow),
+                    GTK_ARROW_DOWN,
+                    GTK_SHADOW_IN);
+      break;
+
+    case GTK_TREE_SORT_DESCENDING:
+      gtk_arrow_set (GTK_ARROW (arrow),
+                    GTK_ARROW_UP,
+                    GTK_SHADOW_IN);
+      break;
+          
+    default:
+      g_warning (G_STRLOC": bad sort order");
+      break;
+    }
+
+  /* Put arrow on the right if the text is left-or-center justified,
+       * and on the left otherwise; do this by packing boxes, so flipping
+       * text direction will reverse things
+       */
+  gtk_widget_ref (arrow);
+  gtk_container_remove (GTK_CONTAINER (hbox), arrow);
+
+  if (tree_column->xalign <= 0.5)
+    {
+      gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
+    }
+  else
+    {
+      gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
+      /* move it to the front */
+      gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
+    }
+  gtk_widget_unref (arrow);
+
+  if (tree_column->show_sort_indicator)
+    gtk_widget_show (arrow);
+  else
+    gtk_widget_hide (arrow);
+
+  /* It's always safe to hide the button.  It isn't always safe to show it, as if you show it
+   * before it's realized, it'll get the wrong window. */
+  if (tree_column->button &&
+      tree_column->tree_view != NULL &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
+    {
+      if (tree_column->visible)
+       {
+         gtk_widget_show (tree_column->button);
+         if (tree_column->window)
+           {
+             if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_RESIZEABLE)
+               {
+                 gdk_window_show (tree_column->window);
+                 gdk_window_raise (tree_column->window);
+               }
+             else
+               {
+                 gdk_window_hide (tree_column->window);
+               }
+           }
+       }
+      else
+       {
+         gtk_widget_hide (tree_column->button);
+         if (tree_column->window)
+           gdk_window_hide (tree_column->window);
+       }
+    }
+
+  tree_column->dirty = TRUE;
+  gtk_widget_queue_resize (tree_column->tree_view);
+}
+
+/* Button signal handlers
+ */
 
 static gint
-gtk_tree_view_passive_func (GtkWidget *widget,
-                           GdkEvent  *event,
-                           gpointer   data)
+gtk_tree_view_column_button_passive_func (GtkWidget *widget,
+                                         GdkEvent  *event,
+                                         gpointer   data)
 {
   g_return_val_if_fail (event != NULL, FALSE);
 
@@ -459,137 +712,191 @@ gtk_tree_view_passive_func (GtkWidget *widget,
 }
 
 static void
-gtk_real_tree_column_clicked (GtkTreeViewColumn *tree_column)
+gtk_tree_view_column_button_realize (GtkWidget *widget, gpointer data)
 {
-  g_return_if_fail (tree_column != NULL);
-  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
-
+  gdk_window_set_events (widget->window, gdk_window_get_events (widget->window) | GDK_POINTER_MOTION_MASK);
 }
 
-
 static void
-gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
+gtk_tree_view_column_button_pressed (GtkWidget *widget, gpointer data)
 {
-  g_signal_emit_by_name (G_OBJECT (data), "clicked");
+  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) data;
+
+  if (! tree_column->reorderable)
+    return;
+
+  tree_column->maybe_reordered = TRUE;
+  gdk_window_get_pointer (widget->window,
+                         &tree_column->drag_x,
+                         &tree_column->drag_y,
+                         NULL);
 }
 
+
 static void
 gtk_tree_view_column_button_released (GtkWidget *widget, gpointer data)
 {
-  GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
+  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) data;
 
-  gtk_widget_show (widget);
-  column->maybe_reordered = FALSE;
+  tree_column->maybe_reordered = FALSE;
+}
+
+static void
+gtk_tree_view_column_button_clicked (GtkWidget *widget, gpointer data)
+{
+  g_signal_emit_by_name (G_OBJECT (data), "clicked");
 }
+
 static gint
 gtk_tree_view_column_button_motion_event (GtkWidget      *widget,
                                          GdkEventMotion *event,
                                          gpointer        data)
 {
-  GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
+  GtkTreeViewColumn *tree_column = (GtkTreeViewColumn *) data;
 
-  if ((column->maybe_reordered) &&
+  if ((tree_column->maybe_reordered) &&
       (gtk_drag_check_threshold (widget,
-                                column->drag_x,
-                                column->drag_y,
+                                tree_column->drag_x,
+                                tree_column->drag_y,
                                 (gint) event->x,
                                 (gint) event->y)))
     {
-      column->maybe_reordered = FALSE;
-      _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (column->tree_view),
-                                       column);
+      tree_column->maybe_reordered = FALSE;
+      _gtk_tree_view_column_start_drag (GTK_TREE_VIEW (tree_column->tree_view), tree_column);
     }
 
   return TRUE;
 }
 
 static void
-gtk_tree_view_column_button_realize (GtkWidget *widget, gpointer data)
+gtk_tree_view_model_property_changed (GtkTreeView        *view,
+                                     guint               n_pspecs,
+                                     GParamSpec        **pspecs,
+                                     GtkTreeViewColumn  *tree_column)
 {
-  gdk_window_set_events (widget->window, gdk_window_get_events (widget->window) | GDK_POINTER_MOTION_MASK);
+  gint i;
+
+  for (i = 0; i < n_pspecs; i++)
+    {
+      if (! strcmp (pspecs[i]->name, "model"))
+       {
+         gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
+       }
+    }
 }
 
 static void
-gtk_tree_view_column_button_pressed (GtkWidget *widget, gpointer data)
+gtk_tree_view_model_sort_column_changed (GtkTreeSortable   *sortable,
+                                         GtkTreeViewColumn *column)
 {
-  GtkTreeViewColumn *column = (GtkTreeViewColumn *) data;
-
-  if (! column->reorderable)
-    return;
+  gint sort_column_id;
+  GtkTreeSortOrder order;
 
-  column->maybe_reordered = TRUE;
-  gdk_window_get_pointer (widget->window,
-                         &column->drag_x,
-                         &column->drag_y,
-                         NULL);
+  if (gtk_tree_sortable_get_sort_column_id (sortable,
+                                           &sort_column_id,
+                                           &order))
+    {
+      if (sort_column_id == column->sort_column_id)
+       {
+         gtk_tree_view_column_set_sort_indicator (column, TRUE);
+         gtk_tree_view_column_set_sort_order (column, order);
+       }
+      else
+       {
+         gtk_tree_view_column_set_sort_indicator (column, FALSE);
+       }
+    }
 }
 
-void
-_gtk_tree_view_column_create_button (GtkTreeViewColumn *column)
+static void
+gtk_tree_view_column_sort (GtkTreeViewColumn *tree_column,
+                          gpointer           data)
 {
-  GtkTreeView *tree_view;
-  GtkWidget *child;
-  GtkWidget *hbox;
+  GList *list;
 
-  tree_view = (GtkTreeView *) column->tree_view;
+  g_return_if_fail (tree_column->tree_view != NULL);
 
-  g_return_if_fail (tree_view != NULL);
-  g_return_if_fail (GTK_IS_TREE_VIEW (tree_view));
-  g_return_if_fail (column->button == NULL);
+  if (tree_column->show_sort_indicator)
+    {
+      if (tree_column->sort_order == GTK_TREE_SORT_ASCENDING)
+       gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_DESCENDING);
+      else
+       gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+    }
+  else
+    {
+      gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+      gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
+    }
 
-  gtk_widget_push_composite_child ();
-  column->button = gtk_button_new ();
-  gtk_widget_pop_composite_child ();
+  list = (GTK_TREE_VIEW (tree_column->tree_view)->priv->columns);
+  g_assert (list);
+  while (list)
+    {
+      GtkTreeViewColumn *tmp_column;
 
-  /* make sure we own a reference to it as well. */
-  gtk_widget_set_parent (column->button, GTK_WIDGET (tree_view));
-  
-  gtk_signal_connect (GTK_OBJECT (column->button), "realize",
-                     (GtkSignalFunc) gtk_tree_view_column_button_realize,
-                     NULL);
-  gtk_signal_connect (GTK_OBJECT (column->button), "clicked",
-                     (GtkSignalFunc) gtk_tree_view_column_button_clicked,
-                     (gpointer) column);
-  gtk_signal_connect (GTK_OBJECT (column->button), "pressed",
-                     (GtkSignalFunc) gtk_tree_view_column_button_pressed,
-                     (gpointer) column);
-  gtk_signal_connect (GTK_OBJECT (column->button), "motion_notify_event",
-                     (GtkSignalFunc) gtk_tree_view_column_button_motion_event,
-                     (gpointer) column);
-  gtk_signal_connect (GTK_OBJECT (column->button), "released",
-                     (GtkSignalFunc) gtk_tree_view_column_button_released,
-                     (gpointer) column);
+      tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
+      if (tmp_column->visible && tmp_column != tree_column)
+       gtk_tree_view_column_set_sort_indicator (tmp_column, FALSE);
 
-  column->alignment = gtk_alignment_new (column->xalign, 0.5, 0.0, 0.0);
+      list = list->next;
+    }
 
-  hbox = gtk_hbox_new (FALSE, 2);
-  column->arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN);
+  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
+                                       tree_column->sort_column_id,
+                                       tree_column->sort_order);
+}
 
-  if (column->child)
-    child = column->child;
-  else
+
+static void
+gtk_tree_view_column_setup_sort_column_id_callback (GtkTreeViewColumn *tree_column)
+{
+  GtkTreeModel *model;
+
+  if (tree_column->tree_view == NULL)
+    return;
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
+
+  if (model == NULL)
     {
-      child = gtk_label_new (column->title);
-      gtk_widget_show (child);
+      if (tree_column->sort_column_changed_signal)
+       {
+         g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
+         tree_column->sort_column_changed_signal = 0;
+       }
+      return;
     }
 
-  if (column->xalign <= 0.5)
-    gtk_box_pack_end (GTK_BOX (hbox), column->arrow, FALSE, FALSE, 0);
-  else
-    gtk_box_pack_start (GTK_BOX (hbox), column->arrow, FALSE, FALSE, 0);
+  if (GTK_IS_TREE_SORTABLE (model) &&
+      tree_column->sort_column_id != -1)
+    {
+      gint real_sort_column_id;
+      GtkTreeSortOrder real_order;
+
+      if (tree_column->sort_column_changed_signal == 0)
+       tree_column->sort_column_changed_signal =
+         g_signal_connectc (G_OBJECT (model), "sort_column_changed",
+                            GTK_SIGNAL_FUNC (gtk_tree_view_model_sort_column_changed),
+                            tree_column, FALSE);
+
+      if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
+                                               &real_sort_column_id,
+                                               &real_order) &&
+         (real_sort_column_id == tree_column->sort_column_id))
+       {
+         gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
+         gtk_tree_view_column_set_sort_order (tree_column, real_order);
 
-  gtk_box_pack_start (GTK_BOX (hbox), column->alignment, TRUE, TRUE, 0);
-        
-  gtk_container_add (GTK_CONTAINER (column->alignment), child);
-  gtk_container_add (GTK_CONTAINER (column->button), hbox);
+         return;
+       }
+    }
+}
 
-  if (column->visible)
-    gtk_widget_show (column->button);
 
-  gtk_widget_show (hbox);
-  gtk_widget_show (column->alignment);
-  update_button_contents (column);
-}
+/* Exported Private Functions.
+ * These should only be called by gtktreeview.c or gtktreeviewcolumn.c
+ */
 
 void
 _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
@@ -606,6 +913,11 @@ _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
   g_return_if_fail (tree_view->priv->header_window != NULL);
   g_return_if_fail (column->button != NULL);
 
+  gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
+
+  if (column->visible)
+    gtk_widget_show (column->button);
+
   attr.window_type = GDK_WINDOW_CHILD;
   attr.wclass = GDK_INPUT_ONLY;
   attr.visual = gtk_widget_get_visual (GTK_WIDGET (tree_view));
@@ -624,13 +936,13 @@ _gtk_tree_view_column_realize_button (GtkTreeViewColumn *column)
   attr.width = TREE_VIEW_DRAG_WIDTH;
   attr.height = tree_view->priv->header_height;
 
-  gtk_widget_set_parent_window (column->button, tree_view->priv->header_window);
-
   attr.x = (column->button->allocation.x + column->button->allocation.width) - 3;
           
   column->window = gdk_window_new (tree_view->priv->header_window,
                                   &attr, attributes_mask);
   gdk_window_set_user_data (column->window, tree_view);
+
+  gtk_tree_view_column_update_button (column);
 }
 
 void
@@ -644,70 +956,21 @@ _gtk_tree_view_column_unrealize_button (GtkTreeViewColumn *column)
   column->window = NULL;
 }
 
-static void
-gtk_tree_view_column_model_changed (GtkTreeView        *view,
-                                   guint               n_pspecs,
-                                   GParamSpec        **pspecs,
-                                   GtkTreeViewColumn  *column)
-{
-  gint i;
-
-  for (i = 0; i < n_pspecs; i++)
-    {
-      if (! strcmp (pspecs[i]->name, "model") &&
-         (column->sort_clicked_signal))
-       {
-         GtkTreeModel *model;
-         if (column->sort_column_changed_signal)
-           g_signal_handler_disconnect (G_OBJECT (column),
-                                        column->sort_column_changed_signal);
-         model = gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view));
-         if (model)
-           column->sort_column_changed_signal =
-             g_signal_connectc (G_OBJECT (model), "sort_column_changed",
-                                GTK_SIGNAL_FUNC (gtk_tree_view_column_sort_column_changed),
-                                column, FALSE);
-         else
-           column->sort_column_changed_signal = 0;
-       }
-    }
-}
-
 void
 _gtk_tree_view_column_set_tree_view (GtkTreeViewColumn *column,
                                     GtkTreeView       *tree_view)
 {
-  column->tree_view = GTK_WIDGET (tree_view);
-  column->model_changed_signal =
-    gtk_signal_connect (GTK_OBJECT (tree_view),
-                       "properties_changed",
-                       GTK_SIGNAL_FUNC (gtk_tree_view_column_model_changed),
-                       column);
-
-  if (column->sort_clicked_signal)
-    {
-      GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (column->tree_view));
+  g_assert (column->tree_view == NULL);
 
-      if (GTK_IS_TREE_SORTABLE (model))
-       {
-         gint real_sort_column_id;
-         GtkTreeSortOrder real_order;
+  column->tree_view = GTK_WIDGET (tree_view);
+  gtk_tree_view_column_create_button (column);
 
-         if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
-                                                   &real_sort_column_id,
-                                                   &real_order) &&
-             (real_sort_column_id == column->sort_column_id))
-           {
-             gtk_tree_view_column_set_sort_indicator (column, TRUE);
-             gtk_tree_view_column_set_sort_order (column, real_order);
-           }
-         column->sort_column_changed_signal =
-           g_signal_connectc (G_OBJECT (model), "sort_column_changed",
-                              GTK_SIGNAL_FUNC (gtk_tree_view_column_sort_column_changed),
-                              column, FALSE);
+  column->property_changed_signal = gtk_signal_connect (GTK_OBJECT (tree_view),
+                                                       "properties_changed",
+                                                       GTK_SIGNAL_FUNC (gtk_tree_view_model_property_changed),
+                                                       column);
 
-       }
-    }
+  gtk_tree_view_column_setup_sort_column_id_callback (column);
 }
 
 void
@@ -717,14 +980,44 @@ _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
     {
       gtk_container_remove (GTK_CONTAINER (column->tree_view), column->button);
     }
-  g_signal_handler_disconnect (G_OBJECT (column->tree_view),
-                              column->model_changed_signal);
-  column->model_changed_signal = 0;
+  if (column->property_changed_signal)
+    {
+      g_signal_handler_disconnect (G_OBJECT (column->tree_view), column->property_changed_signal);
+      column->property_changed_signal = 0;
+    }
+
+  if (column->sort_column_changed_signal)
+    {
+      g_signal_handler_disconnect (G_OBJECT (column), column->sort_column_changed_signal);
+      column->sort_column_changed_signal = 0;
+    }
+
   column->tree_view = NULL;
   column->button = NULL;
 }
 
+void
+_gtk_tree_view_column_set_width (GtkTreeViewColumn *tree_column,
+                                gint               width)
+{
+  if (tree_column->min_width != -1 &&
+      width <= tree_column->min_width)
+    width = tree_column->min_width;
+  else if (tree_column->max_width != -1 &&
+           width > tree_column->max_width)
+    width = tree_column->max_width;
+  
+  if (tree_column->width == width)
+    return;
+  
+  tree_column->width = width;
+
+  g_object_notify (G_OBJECT (tree_column), "width");
+
+  if (tree_column->tree_view != NULL)
+    gtk_widget_queue_resize (tree_column->tree_view);
 
+}
 
 /* Public Functions */
 
@@ -739,11 +1032,11 @@ _gtk_tree_view_column_unset_tree_view (GtkTreeViewColumn *column)
 GtkTreeViewColumn *
 gtk_tree_view_column_new (void)
 {
-  GtkTreeViewColumn *retval;
+  GtkTreeViewColumn *tree_column;
 
-  retval = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
+  tree_column = GTK_TREE_VIEW_COLUMN (gtk_type_new (GTK_TYPE_TREE_VIEW_COLUMN));
 
-  return retval;
+  return tree_column;
 }
 
 /**
@@ -805,6 +1098,12 @@ gtk_tree_view_column_set_cell_renderer (GtkTreeViewColumn *tree_column,
 
   tree_column->cell = cell;
 
+  if (tree_column->tree_view)
+    {
+      tree_column->dirty = TRUE;
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
+
   g_object_notify (G_OBJECT (tree_column), "cell_renderer");
 }
 
@@ -846,6 +1145,13 @@ gtk_tree_view_column_add_attribute (GtkTreeViewColumn *tree_column,
                                             GINT_TO_POINTER (column));
   tree_column->attributes = g_slist_prepend (tree_column->attributes,
                                             g_strdup (attribute));
+
+  if (tree_column->tree_view)
+    {
+      tree_column->dirty = TRUE;
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
+
 }
 
 static void
@@ -920,12 +1226,23 @@ gtk_tree_view_column_set_cell_data_func (GtkTreeViewColumn *tree_column,
   g_return_if_fail (tree_column != NULL);
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
+  if (func == tree_column->func &&
+      func_data == tree_column->func_data &&
+      destroy == tree_column->destroy)
+    return;
+
   if (tree_column->func_data && tree_column->destroy)
     (tree_column->destroy) (tree_column->func_data);
 
   tree_column->func = func;
   tree_column->func_data = func_data;
   tree_column->destroy = destroy;
+
+  if (tree_column->tree_view)
+    {
+      tree_column->dirty = TRUE;
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
 }
 
 
@@ -952,6 +1269,12 @@ gtk_tree_view_column_clear_attributes (GtkTreeViewColumn *tree_column)
     }
   g_slist_free (tree_column->attributes);
   tree_column->attributes = NULL;
+
+  if (tree_column->tree_view)
+    {
+      tree_column->dirty = TRUE;
+      gtk_widget_queue_resize (tree_column->tree_view);
+    }
 }
 
 /**
@@ -1022,29 +1345,11 @@ gtk_tree_view_column_set_visible (GtkTreeViewColumn *tree_column,
   visible = !! visible;
   
   if (tree_column->visible == visible)
-    return;
-
-  tree_column->visible = visible;
-
-  if (tree_column->tree_view != NULL)
-    {
-      if (visible)
-       {
-         gtk_widget_show (tree_column->button);
-         if (GTK_WIDGET_REALIZED (tree_column->tree_view) && tree_column->window)
-           gdk_window_show (tree_column->window);
-       }
-      else
-       {
-         gtk_widget_hide (tree_column->button);
-         if (GTK_WIDGET_REALIZED (tree_column->tree_view) && tree_column->window)
-           gdk_window_hide (tree_column->window);
-       }
+    return;
 
-      if (GTK_WIDGET_REALIZED (tree_column->tree_view))
-       _gtk_tree_view_update_size (GTK_TREE_VIEW (tree_column->tree_view));
-    }
+  tree_column->visible = visible;
 
+  gtk_tree_view_column_update_button (tree_column);
   g_object_notify (G_OBJECT (tree_column), "visible");
 }
 
@@ -1074,7 +1379,7 @@ gtk_tree_view_column_get_visible (GtkTreeViewColumn *tree_column)
  * Sets the growth behavior of @tree_column to @type.
  **/
 void
-gtk_tree_view_column_set_sizing (GtkTreeViewColumn     *tree_column,
+gtk_tree_view_column_set_sizing (GtkTreeViewColumn       *tree_column,
                                  GtkTreeViewColumnSizing  type)
 {
   g_return_if_fail (tree_column != NULL);
@@ -1083,31 +1388,17 @@ gtk_tree_view_column_set_sizing (GtkTreeViewColumn     *tree_column,
   if (type == tree_column->column_type)
     return;
 
-  tree_column->column_type = type;
-
-  g_object_notify (G_OBJECT (tree_column), "sizing");
-
-  if (tree_column->tree_view == NULL)
-    return;
-
-  switch (type)
+  if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE &&
+      tree_column->requested_width != -1)
     {
-    case GTK_TREE_VIEW_COLUMN_AUTOSIZE:
-      tree_column->dirty = TRUE;
-    case GTK_TREE_VIEW_COLUMN_FIXED:
-      if (GTK_WIDGET_REALIZED (tree_column->tree_view))
-        gdk_window_hide (tree_column->window);
-      break;
-    default:
-      if (GTK_WIDGET_REALIZED (tree_column->tree_view))
-        {
-          gdk_window_show (tree_column->window);
-          gdk_window_raise (tree_column->window);
-        }
-      break;
+      gtk_tree_view_column_set_sizing (tree_column, tree_column->requested_width);
     }
+  tree_column->column_type = type;
 
-  gtk_widget_queue_resize (tree_column->tree_view);
+  gtk_tree_view_column_update_button (tree_column);
+
+  if (type != GTK_TREE_VIEW_COLUMN_AUTOSIZE)
+  g_object_notify (G_OBJECT (tree_column), "sizing");
 }
 
 /**
@@ -1147,7 +1438,7 @@ gtk_tree_view_column_get_size (GtkTreeViewColumn *tree_column)
 /**
  * gtk_tree_view_column_set_width:
  * @tree_column: A #GtkTreeViewColumn.
- * @size: The size to set the @tree_column to.
+ * @width: The size to set the @tree_column to.
  * 
  * Sets the size of the column in pixels, unless the the column type is
  * #GTK_TREE_VIEW_COLUMN_AUTOSIZE.  In this case, the value is discarded as the
@@ -1156,32 +1447,17 @@ gtk_tree_view_column_get_size (GtkTreeViewColumn *tree_column)
  **/
 void
 gtk_tree_view_column_set_width (GtkTreeViewColumn *tree_column,
-                                gint               size)
+                                gint               width)
 {
   g_return_if_fail (tree_column != NULL);
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
-  g_return_if_fail (size > 0);
-  
-  if (tree_column->min_width != -1 &&
-      size <= tree_column->min_width)
-    size = tree_column->min_width;
-  else if (tree_column->max_width != -1 &&
-           size > tree_column->max_width)
-    size = tree_column->max_width;
-  
-  if (tree_column->width == size)
-    return;
-  
-  tree_column->width = size;
+  g_return_if_fail (width > 0);
 
-  
-  g_object_notify (G_OBJECT (tree_column), "width");
-
-  if (tree_column->tree_view == NULL)
+  if (tree_column->column_type == GTK_TREE_VIEW_COLUMN_AUTOSIZE)
     return;
 
-  if (GTK_WIDGET_REALIZED (tree_column->tree_view))
-    gtk_widget_queue_resize (tree_column->tree_view);
+  tree_column->requested_width = width;
+  _gtk_tree_view_column_set_width (tree_column, width);
 }
 
 /**
@@ -1226,17 +1502,19 @@ gtk_tree_view_column_set_min_width (GtkTreeViewColumn *tree_column,
 
   /* We want to queue a resize if the either the old min_size or the
    * new min_size determined the size of the column */
-  if (GTK_WIDGET_REALIZED (tree_column->tree_view) &&
-      ((tree_column->min_width > tree_column->width) ||
-       (tree_column->min_width == -1 &&
-       tree_column->button->requisition.width > tree_column->width) ||
-       (min_width > tree_column->width) ||
-       (min_width == -1 &&
-       tree_column->button->requisition.width > tree_column->width)))
-    gtk_widget_queue_resize (tree_column->tree_view);
+  if (tree_column->tree_view &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view))
+    {
+      if ((tree_column->min_width > tree_column->width) ||
+         (tree_column->min_width == -1 &&
+          tree_column->button->requisition.width > tree_column->width) ||
+         (min_width > tree_column->width) ||
+         (min_width == -1 &&
+          tree_column->button->requisition.width > tree_column->width))
+       gtk_widget_queue_resize (tree_column->tree_view);
+    }
 
-  if (tree_column->max_width != -1 &&
-      tree_column->max_width < real_min_width)
+  if (tree_column->max_width != -1 && tree_column->max_width < real_min_width)
     tree_column->max_width = real_min_width;
 
   tree_column->min_width = min_width;
@@ -1286,7 +1564,8 @@ gtk_tree_view_column_set_max_width (GtkTreeViewColumn *tree_column,
   real_min_width = tree_column->min_width == -1 ?
     tree_column->button->requisition.width : tree_column->min_width;
 
-  if (GTK_WIDGET_REALIZED (tree_column->tree_view) &&
+  if (tree_column->tree_view &&
+      GTK_WIDGET_REALIZED (tree_column->tree_view) &&
       ((tree_column->max_width < tree_column->width) ||
        (max_width != -1 && max_width < tree_column->width)))
     gtk_widget_queue_resize (tree_column->tree_view);
@@ -1321,111 +1600,18 @@ gtk_tree_view_column_get_max_width (GtkTreeViewColumn *tree_column)
  * gtk_tree_view_column_clicked:
  * @tree_column: a #GtkTreeViewColumn
  * 
- * Emits the "clicked" signal on the column.
+ * Emits the "clicked" signal on the column.  This function will only work if
+ * the user could have conceivably clicked on the button.
  **/
 void
 gtk_tree_view_column_clicked (GtkTreeViewColumn *tree_column)
 {
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
-  gtk_signal_emit (GTK_OBJECT (tree_column), tree_column_signals[CLICKED]);
-}
-
-static void 
-update_button_contents (GtkTreeViewColumn *tree_column)
-{
-  GtkWidget *hbox;
-  GtkWidget *alignment;
-  GtkWidget *arrow;
-  GtkWidget *current_child;
-
-  if (! tree_column->button)
-    return;
-
-  hbox = GTK_BIN (tree_column->button)->child;
-  alignment = tree_column->alignment;
-  arrow = tree_column->arrow;
-  current_child = GTK_BIN (alignment)->child;
-
-  gtk_alignment_set (GTK_ALIGNMENT (alignment), tree_column->xalign,
-                    0.5, 0.0, 0.0);
-      
-  if (tree_column->child)
-    {
-      if (current_child != tree_column->child)
-       {
-         gtk_container_remove (GTK_CONTAINER (alignment),
-                               current_child);
-
-         gtk_container_add (GTK_CONTAINER (alignment),
-                            tree_column->child);
-       }
-    }
-  else 
-    {
-      if (current_child == NULL)
-       {
-         current_child = gtk_label_new (NULL);
-
-         gtk_widget_show (current_child);
-              
-         gtk_container_add (GTK_CONTAINER (alignment),
-                            current_child);
-       }
-
-      g_return_if_fail (GTK_IS_LABEL (current_child));
-
-      if (tree_column->title)
-       gtk_label_set_text (GTK_LABEL (current_child),
-                           tree_column->title);
-      else
-       gtk_label_set_text (GTK_LABEL (current_child),
-                           "");
-    }
-
-  switch (tree_column->sort_order)
-    {
-    case GTK_TREE_SORT_ASCENDING:
-      gtk_arrow_set (GTK_ARROW (arrow),
-                    GTK_ARROW_DOWN,
-                    GTK_SHADOW_IN);
-      break;
-
-    case GTK_TREE_SORT_DESCENDING:
-      gtk_arrow_set (GTK_ARROW (arrow),
-                    GTK_ARROW_UP,
-                    GTK_SHADOW_IN);
-      break;
-          
-    default:
-      g_warning (G_STRLOC": bad sort order");
-      break;
-    }
-
-  /* Put arrow on the right if the text is left-or-center justified,
-       * and on the left otherwise; do this by packing boxes, so flipping
-       * text direction will reverse things
-       */
-  gtk_widget_ref (arrow);
-  gtk_container_remove (GTK_CONTAINER (hbox), arrow);
-
-  if (tree_column->xalign <= 0.5)
-    {
-      gtk_box_pack_end (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
-    }
-  else
-    {
-      gtk_box_pack_start (GTK_BOX (hbox), arrow, FALSE, FALSE, 0);
-      /* move it to the front */
-      gtk_box_reorder_child (GTK_BOX (hbox), arrow, 0);
-    }
-
-  gtk_widget_unref (arrow);
-
-  if (tree_column->show_sort_indicator)
-    gtk_widget_show (arrow);
-  else
-    gtk_widget_hide (arrow);
+  if (tree_column->visible &&
+      tree_column->button &&
+      tree_column->clickable)
+    gtk_button_clicked (GTK_BUTTON (tree_column->button));
 }
 
 /**
@@ -1449,7 +1635,7 @@ gtk_tree_view_column_set_title (GtkTreeViewColumn *tree_column,
   else
     tree_column->title = NULL;
 
-  update_button_contents (tree_column);
+  gtk_tree_view_column_update_button (tree_column);
 
   g_object_notify (G_OBJECT (tree_column), "title");
 }
@@ -1471,52 +1657,59 @@ gtk_tree_view_column_get_title (GtkTreeViewColumn *tree_column)
   return tree_column->title;
 }
 
-/**
- * gtk_tree_view_column_set_clickable:
- * @tree_column: A #GtkTreeViewColumn.
- * @active: TRUE if the header is active.
- * 
- * Sets the header to be active if @active is TRUE.  When the header is active,
- * then it can take keyboard focus, and can be clicked.
- **/
-void
-gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
-                                    gboolean           active)
-{
-  g_return_if_fail (tree_column != NULL);
-  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
+static void
+gtk_tree_view_column_set_clickable_real (GtkTreeViewColumn *tree_column)
+{
   if (!tree_column->button)
     return;
 
-  if (tree_column->button_active == active)
-    return;
-
-  tree_column->button_active = active;
-  if (active)
+  if (tree_column->clickable)
     {
-      gtk_signal_disconnect_by_func (GTK_OBJECT (tree_column->button),
-                                    (GtkSignalFunc) gtk_tree_view_passive_func,
-                                    NULL);
+      if (tree_column->clickable_signal)
+       {
+         g_signal_handler_disconnect (G_OBJECT (tree_column->button), tree_column->clickable_signal);
+         tree_column->clickable_signal = 0;
+       }
 
       GTK_WIDGET_SET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
-
       if (GTK_WIDGET_VISIBLE (tree_column->tree_view))
        gtk_widget_queue_draw (tree_column->button);
     }
   else
     {
-      gtk_signal_connect (GTK_OBJECT (tree_column->button),
-                         "event",
-                         (GtkSignalFunc) gtk_tree_view_passive_func,
-                         NULL);
+      tree_column->clickable_signal =
+       gtk_signal_connect (GTK_OBJECT (tree_column->button),
+                           "event",
+                           (GtkSignalFunc) gtk_tree_view_column_button_passive_func,
+                           NULL);
 
       GTK_WIDGET_UNSET_FLAGS (tree_column->button, GTK_CAN_FOCUS);
-
       if (GTK_WIDGET_VISIBLE (tree_column->tree_view))
        gtk_widget_queue_draw (tree_column->button);
     }
 
+}
+
+/**
+ * gtk_tree_view_column_set_clickable:
+ * @tree_column: A #GtkTreeViewColumn.
+ * @clickable: TRUE if the header is active.
+ * 
+ * Sets the header to be active if @active is TRUE.  When the header is active,
+ * then it can take keyboard focus, and can be clicked.
+ **/
+void
+gtk_tree_view_column_set_clickable (GtkTreeViewColumn *tree_column,
+                                    gboolean           clickable)
+{
+  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
+
+  if (tree_column->clickable == (clickable?TRUE:FALSE))
+    return;
+
+  tree_column->clickable = (clickable?TRUE:FALSE);
+  gtk_tree_view_column_set_clickable_real (tree_column);
   g_object_notify (G_OBJECT (tree_column), "clickable");
 }
 
@@ -1533,7 +1726,7 @@ gtk_tree_view_column_get_clickable (GtkTreeViewColumn *tree_column)
 {
   g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
 
-  return tree_column->button_active;
+  return tree_column->clickable;
 }
 
 /**
@@ -1561,9 +1754,7 @@ gtk_tree_view_column_set_widget (GtkTreeViewColumn *tree_column,
     gtk_object_unref (GTK_OBJECT (tree_column->child));
 
   tree_column->child = widget;
-  
-  update_button_contents (tree_column);
-
+  gtk_tree_view_column_update_button (tree_column);
   g_object_notify (G_OBJECT (tree_column), "widget");
 }
 
@@ -1604,9 +1795,7 @@ gtk_tree_view_column_set_alignment (GtkTreeViewColumn *tree_column,
     return;
 
   tree_column->xalign = xalign;
-
-  update_button_contents (tree_column);
-
+  gtk_tree_view_column_update_button (tree_column);
   g_object_notify (G_OBJECT (tree_column), "alignment");
 }
 
@@ -1618,74 +1807,36 @@ gtk_tree_view_column_get_alignment (GtkTreeViewColumn *tree_column)
   return tree_column->xalign;
 }
 
-static void
-gtk_tree_view_column_sort_column_changed (GtkTreeSortable   *sortable,
-                                         GtkTreeViewColumn *column)
+void
+gtk_tree_view_column_set_reorderable (GtkTreeViewColumn *tree_column,
+                                     gboolean           reorderable)
 {
-  gint sort_column_id;
-  GtkTreeSortOrder order;
+  g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
-  if (gtk_tree_sortable_get_sort_column_id (sortable,
-                                           &sort_column_id,
-                                           &order))
-    {
-      if (sort_column_id == column->sort_column_id)
-       {
-         gtk_tree_view_column_set_sort_indicator (column, TRUE);
-         gtk_tree_view_column_set_sort_order (column, order);
-       }
-      else
-       {
-         gtk_tree_view_column_set_sort_indicator (column, FALSE);
-       }
-    }
+  if (tree_column->reorderable == (reorderable?TRUE:FALSE))
+    return;
+
+  tree_column->reorderable = (reorderable?TRUE:FALSE);
+  gtk_tree_view_column_update_button (tree_column);
+  g_object_notify (G_OBJECT (tree_column), "reorderable");
 }
 
-static void
-sort_clicked_func (GtkTreeViewColumn *tree_column,
-                  gpointer           data)
+gboolean
+gtk_tree_view_column_get_reorderable (GtkTreeViewColumn *tree_column)
 {
-  GList *list;
-
-  g_return_if_fail (tree_column->tree_view != NULL);
-
-  if (tree_column->show_sort_indicator)
-    {
-      if (tree_column->sort_order == GTK_TREE_SORT_ASCENDING)
-       gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_DESCENDING);
-      else
-       gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
-    }
-  else
-    {
-      gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
-      gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
-    }
-
-  list = (GTK_TREE_VIEW (tree_column->tree_view)->priv->columns);
-  g_assert (list);
-  while (list)
-    {
-      GtkTreeViewColumn *tmp_column;
-
-      tmp_column = GTK_TREE_VIEW_COLUMN (list->data);
-      if (tmp_column->visible && tmp_column != tree_column)
-       gtk_tree_view_column_set_sort_indicator (tmp_column, FALSE);
-
-      list = list->next;
-    }
+  g_return_val_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column), FALSE);
 
-  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (GTK_TREE_VIEW (tree_column->tree_view)->priv->model),
-                                       tree_column->sort_column_id,
-                                       tree_column->sort_order);
+  return tree_column->reorderable;
 }
 
+
 /**
  * gtk_tree_view_column_set_sort_column_id:
  * @tree_column: a #GtkTreeViewColumn
  * @sort_column_id: The sort_column_id of the model to sort on.
  * 
- * Sets the sort_column_id that the column sorts on.
+ * Sets the sort_column_id that the column sorts on.  Doing so makes headers
+ * clickable.
  **/
 void
 gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
@@ -1697,50 +1848,37 @@ gtk_tree_view_column_set_sort_column_id (GtkTreeViewColumn *tree_column,
   if (tree_column->sort_column_id == sort_column_id)
     return;
 
+  tree_column->sort_column_id = sort_column_id;
+
+  /* Handle unsetting the id */
   if (sort_column_id == -1)
     {
       if (tree_column->sort_clicked_signal)
-       g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
+       {
+         g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_clicked_signal);
+         tree_column->sort_clicked_signal = 0;
+       }
+
+      if (tree_column->sort_column_changed_signal)
+       {
+         g_signal_handler_disconnect (G_OBJECT (tree_column), tree_column->sort_column_changed_signal);
+         tree_column->sort_column_changed_signal = 0;
+       }
+
+      gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+      gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
       return;
     }
 
+  gtk_tree_view_column_set_clickable (tree_column, TRUE);
+
   if (! tree_column->sort_clicked_signal)
     tree_column->sort_clicked_signal = g_signal_connectc (G_OBJECT (tree_column),
-                                                 "clicked",
-                                                 G_CALLBACK (sort_clicked_func),
-                                                 NULL, FALSE);
-  tree_column->sort_column_id = sort_column_id;
-
-  if (tree_column->tree_view)
-    {
-      GtkTreeModel *model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_column->tree_view));
+                                                         "clicked",
+                                                         G_CALLBACK (gtk_tree_view_column_sort),
+                                                         NULL, FALSE);
 
-      if (GTK_IS_TREE_SORTABLE (model))
-       {
-         gint real_sort_column_id;
-         GtkTreeSortOrder real_order;
-
-         if (tree_column->sort_column_changed_signal == 0)
-           tree_column->sort_column_changed_signal =
-             g_signal_connectc (G_OBJECT (model), "sort_column_changed",
-                                GTK_SIGNAL_FUNC (gtk_tree_view_column_sort_column_changed),
-                                tree_column, FALSE);
-
-         if (gtk_tree_sortable_get_sort_column_id (GTK_TREE_SORTABLE (model),
-                                                   &real_sort_column_id,
-                                                   &real_order) &&
-             (real_sort_column_id == sort_column_id))
-           {
-             gtk_tree_view_column_set_sort_indicator (tree_column, TRUE);
-             gtk_tree_view_column_set_sort_order (tree_column, real_order);
-
-             return;
-           }
-       }
-    }
-
-  gtk_tree_view_column_set_sort_indicator (tree_column, FALSE);
-  gtk_tree_view_column_set_sort_order (tree_column, GTK_TREE_SORT_ASCENDING);
+  gtk_tree_view_column_setup_sort_column_id_callback (tree_column);
 }
 
 /**
@@ -1762,16 +1900,12 @@ gtk_tree_view_column_set_sort_indicator (GtkTreeViewColumn     *tree_column,
 
   setting = setting != FALSE;
 
-  if (setting != tree_column->show_sort_indicator)
-    {
-      tree_column->show_sort_indicator = setting;
-
-      update_button_contents (tree_column);
+  if (setting == tree_column->show_sort_indicator)
+    return;
 
-      g_object_notify (G_OBJECT (tree_column), "sort_indicator");
-      if (GTK_WIDGET_REALIZED (tree_column->tree_view))
-       gtk_widget_queue_draw (tree_column->tree_view);
-    }
+  tree_column->show_sort_indicator = setting;
+  gtk_tree_view_column_update_button (tree_column);
+  g_object_notify (G_OBJECT (tree_column), "sort_indicator");
 }
 
 /**
@@ -1800,7 +1934,7 @@ gtk_tree_view_column_get_sort_indicator  (GtkTreeViewColumn     *tree_column)
  * gtk_tree_view_column_set_sort_column_id() if you want automatic sorting
  * support.  This function is primarily for custom sorting behavior, and should
  * be used in conjunction with #gtk_tree_sortable_set_sort_column() to do
- * that. For custom models, the mechanism will vary.) The sort indicator changes
+ * that. For custom models, the mechanism will vary. The sort indicator changes
  * direction to indicate normal sort or reverse sort. Note that you must have
  * the sort indicator enabled to see anything when calling this function; see
  * gtk_tree_view_column_set_sort_indicator().
@@ -1812,14 +1946,12 @@ gtk_tree_view_column_set_sort_order      (GtkTreeViewColumn     *tree_column,
 {
   g_return_if_fail (GTK_IS_TREE_VIEW_COLUMN (tree_column));
 
-  if (order != tree_column->sort_order)
-    {
-      tree_column->sort_order = order;
+  if (order == tree_column->sort_order)
+    return;
 
-      update_button_contents (tree_column);
-      
-      g_object_notify (G_OBJECT (tree_column), "sort_order");
-    }
+  tree_column->sort_order = order;
+  gtk_tree_view_column_update_button (tree_column);
+  g_object_notify (G_OBJECT (tree_column), "sort_order");
 }
 
 /**
@@ -1839,3 +1971,4 @@ gtk_tree_view_column_get_sort_order      (GtkTreeViewColumn     *tree_column)
 }
 
 
+
index 779edb39db2ba9fab4a906591ae682b5674d0f6c..394e2aedec3e966d46d045571ffead6bf4159894 100644 (file)
@@ -63,9 +63,11 @@ struct _GtkTreeViewColumn
   GtkWidget *alignment;
   GdkWindow *window;
   gfloat xalign;
-  guint model_changed_signal;
+  guint property_changed_signal;
+  guint clickable_signal;
 
   gint width;
+  gint requested_width;
   gint min_width;
   gint max_width;
   gint displayed_width;
@@ -88,12 +90,12 @@ struct _GtkTreeViewColumn
   gint sort_column_id;
   GtkTreeSortOrder sort_order;
 
-  guint visible       : 1;
-  guint button_active : 1;
-  guint dirty         : 1;
+  guint visible             : 1;
+  guint clickable           : 1;
+  guint dirty               : 1;
   guint show_sort_indicator : 1;
   guint maybe_reordered     : 1;
-  guint reorderable   : 1;
+  guint reorderable         : 1;
 };
 
 struct _GtkTreeViewColumnClass
@@ -150,7 +152,7 @@ void                  gtk_tree_view_column_set_title          (GtkTreeViewColumn
                                                                const gchar       *title);
 G_CONST_RETURN gchar *gtk_tree_view_column_get_title          (GtkTreeViewColumn *tree_column);
 void                  gtk_tree_view_column_set_clickable      (GtkTreeViewColumn *tree_column,
-                                                               gboolean           active);
+                                                               gboolean           clickable);
 gboolean              gtk_tree_view_column_get_clickable      (GtkTreeViewColumn *tree_column);
 void                  gtk_tree_view_column_set_widget         (GtkTreeViewColumn *tree_column,
                                                                GtkWidget         *widget);
@@ -158,7 +160,9 @@ GtkWidget            *gtk_tree_view_column_get_widget         (GtkTreeViewColumn
 void                  gtk_tree_view_column_set_alignment      (GtkTreeViewColumn *tree_column,
                                                                gfloat             xalign);
 gfloat                gtk_tree_view_column_get_alignment      (GtkTreeViewColumn *tree_column);
-
+void                  gtk_tree_view_column_set_reorderable    (GtkTreeViewColumn *tree_column,
+                                                              gboolean           reorderable);
+gboolean              gtk_tree_view_column_get_reorderable    (GtkTreeViewColumn *tree_column);
 
 /* You probably only want to use gtk_tree_view_column_set_sort_column_id.  The
  * other sorting functions exist primarily to let others do their own custom sorting.
index e7e5e144fb2a9fe6a744bb5e05142b4e98ddae1c..db48f25cdef3f7b7daffa30f158b50349e7ec750 100644 (file)
@@ -13,19 +13,26 @@ GtkWidget *sample_tree_view_bottom;
 static void
 add_clicked (GtkWidget *button, gpointer data)
 {
+  static gint i = 0;
+
   GtkTreeIter iter;
   GtkTreeViewColumn *column;
+  GtkTreeSelection *selection;
   GtkCellRenderer *cell;
-  static gint i = 0;
   gchar *label = g_strdup_printf ("Column %d", i);
 
   cell = gtk_cell_renderer_text_new ();
   column = gtk_tree_view_column_new_with_attributes (label, cell, "text", 0, NULL);
+  gtk_tree_view_column_set_reorderable (column, TRUE);
   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_RESIZEABLE);
+  gtk_tree_view_column_set_clickable (column, FALSE);
   gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
   gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
   g_free (label);
   i++;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
+  gtk_tree_selection_select_iter (selection, &iter);
 }
 
 static void
@@ -89,8 +96,11 @@ add_left_clicked (GtkWidget *button, gpointer data)
 
   gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);
 
+  /* Put it back on the left */
   gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
   gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
+  gtk_tree_selection_select_iter (selection, &iter);
   g_free (label);
 }
 
@@ -113,6 +123,9 @@ add_right_clicked (GtkWidget *button, gpointer data)
   gtk_list_store_append (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);
   gtk_list_store_set (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter, 0, label, 1, column, -1);
 
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data));
+  gtk_tree_selection_select_iter (selection, &iter);
+
   if (GTK_WIDGET (data) == top_right_tree_view)
     gtk_tree_view_append_column (GTK_TREE_VIEW (sample_tree_view_top), column);
   else
@@ -129,6 +142,11 @@ selection_changed (GtkTreeSelection *selection, GtkWidget *button)
     gtk_widget_set_sensitive (button, FALSE);
 }
 
+
+static GtkTargetEntry row_targets[] = {
+  { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, 0}
+};
+
 int
 main (int argc, char *argv[])
 {
@@ -198,7 +216,7 @@ main (int argc, char *argv[])
   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (left_tree_view), -1,
                                               "Unattached Columns", cell, "text", 0, NULL);
   cell = gtk_cell_renderer_toggle_new ();
-  g_signal_connect_data (G_OBJECT (cell), "toggled", set_visible, left_tree_view, NULL, FALSE, FALSE);
+  g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, left_tree_view, NULL, FALSE, FALSE);
   column = gtk_tree_view_column_new_with_attributes ("Visible", cell, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (left_tree_view), column);
   g_object_unref (G_OBJECT (column));
@@ -259,7 +277,7 @@ main (int argc, char *argv[])
   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (top_right_tree_view), -1,
                                               NULL, cell, "text", 0, NULL);
   cell = gtk_cell_renderer_toggle_new ();
-  g_signal_connect_data (G_OBJECT (cell), "toggled", set_visible, top_right_tree_view, NULL, FALSE, FALSE);
+  g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, top_right_tree_view, NULL, FALSE, FALSE);
   column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
   gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (top_right_tree_view), column);
@@ -274,7 +292,7 @@ main (int argc, char *argv[])
   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (bottom_right_tree_view), -1,
                                               NULL, cell, "text", 0, NULL);
   cell = gtk_cell_renderer_toggle_new ();
-  g_signal_connect_data (G_OBJECT (cell), "toggled", set_visible, bottom_right_tree_view, NULL, FALSE, FALSE);
+  g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, bottom_right_tree_view, NULL, FALSE, FALSE);
   column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
   gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
   gtk_tree_view_append_column (GTK_TREE_VIEW (bottom_right_tree_view), column);
@@ -282,6 +300,44 @@ main (int argc, char *argv[])
   gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
 
   
+  /* Drag and Drop */
+  gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (left_tree_view),
+                                      GDK_BUTTON1_MASK,
+                                      row_targets,
+                                      G_N_ELEMENTS (row_targets),
+                                      GDK_ACTION_MOVE,
+                                      NULL, NULL);
+  gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (left_tree_view),
+                                    row_targets,
+                                    G_N_ELEMENTS (row_targets),
+                                    GDK_ACTION_MOVE,
+                                    NULL, NULL);
+
+  gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (top_right_tree_view),
+                                      GDK_BUTTON1_MASK,
+                                      row_targets,
+                                      G_N_ELEMENTS (row_targets),
+                                      GDK_ACTION_MOVE,
+                                      NULL, NULL);
+  gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (top_right_tree_view),
+                                   row_targets,
+                                   G_N_ELEMENTS (row_targets),
+                                   GDK_ACTION_MOVE,
+                                     NULL, NULL);
+
+  gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (bottom_right_tree_view),
+                                      GDK_BUTTON1_MASK,
+                                      row_targets,
+                                      G_N_ELEMENTS (row_targets),
+                                      GDK_ACTION_MOVE,
+                                      NULL, NULL);
+  gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (bottom_right_tree_view),
+                                   row_targets,
+                                   G_N_ELEMENTS (row_targets),
+                                   GDK_ACTION_MOVE,
+                                   NULL, NULL);
+
+
   gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
 
   hbox = gtk_hbox_new (FALSE, 8);